#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <dirent.h>
#include <time.h>

#ifndef _AST_HEADER_
#define _AST_HEADER_
#include "../include/ast.h"
#endif

#ifndef _DATABASE_OPERATION_HEADER_
#define _DATABASE_OPERATION_HEADER_
#include "../include/operation.h"
#endif

#ifndef _IDB_HEADER_
#define _IDB_HEADER_
#include "../include/idb.h"
#endif

extern char * m_usingDatabase;
extern TableListStructPoint m_tlsp;
extern DatabaseConfigStructPoint m_databaseConfig;


void initDatabase(){
    FILE * configFile = fopen(m_databaseConfig->configPath,"r");
    if(configFile == NULL){
        perror("fopen");
        handleError(CONFIG_FILE_OPEN_ERROR,m_databaseConfig->configPath);
    }
    while(!feof(configFile)){
        char key[50];
        char value[1000];
        fscanf(configFile,"%s %s",key,value);
        
        if(!strcmp(key,"dataDir")){
            m_databaseConfig->m_dataPath = (char *)malloc(sizeof(char) * (strlen(value) + 1));
            strcpy(m_databaseConfig->m_dataPath,value);
          
        }else if(!strcmp(key,"tabLength")){
            m_databaseConfig->tabLength = atoi(value);
          
        }else if(!strcmp(key,"instruction")){
            m_databaseConfig->m_instructmentPath = (char *)malloc(sizeof(char) * (strlen(value) + 1));
            strcpy(m_databaseConfig->m_instructmentPath,value);
        }else{
            printf("Unknow config: %s\n",key);
        }
        
    }
    printf("close file;\n");
    fclose(configFile);
    if(m_databaseConfig->m_dataPath == NULL){
        m_databaseConfig->m_dataPath = "../data";
    }
}

int calTabCnt(int max){

    int k = (max+2)%m_databaseConfig->tabLength == 0 ? ((max+2)/(m_databaseConfig->tabLength)):((max+1)/(m_databaseConfig->tabLength) + 1); 
    return k;
}

void borderPrint(int cnt)
{
	printf("+");
    int tabLength = m_databaseConfig->tabLength;
    for(int i = 1;i < tabLength;i++){
        printf("-");
    }
	while(--cnt)
	{
		for(int i = 0;i < tabLength;i++){
            printf("-");
        }
	}
}

void contentPrint(char * res,int cnt)
{
	int tem;
	printf("| %s\t",res);
	tem = cnt - (strlen(res)+2)/(m_databaseConfig->tabLength);
	while(--tem)
	{
		printf("\t");
	}
}


void contentIntPrint(int * data,int cnt){
    int tem;
    printf("| %-16d\t",* data);
    tem = cnt - 18/(m_databaseConfig->tabLength);
    while(--tem)
    {
        printf("\t");
    }
}

void contentDoublePrint(double * data,int cnt){
    int tem;
    printf("| %-16.6e\t",* data);
    tem = cnt - 18/(m_databaseConfig->tabLength);
    while(--tem)
    {
        printf("\t");
    }
}

void _exitDatabase(){
    freeGlobalVariable();
    printf("bye!\n");
    exit(0);
}

void freeGlobalVariable(){
    free(m_usingDatabase);
    if(m_tlsp != NULL){
        freeStruct(TABLELIST,m_tlsp);
    }
    freeStruct(DATABASECONFIG,m_databaseConfig);
}

void freeStruct(enum STRUCT type,void * root){
    switch(type){
        case TABLELIST:
        {
            TableListStructPoint tsp  = (TableListStructPoint)root;
            TableListStructPoint next;
            next = tsp->next;
            while(tsp != NULL){
                next = tsp->next;
                free(tsp);
                tsp = next;
            }
            break;
        }
        case DATABASECONFIG:
        {
            DatabaseConfigStructPoint tmp2 = (DatabaseConfigStructPoint) root;
            free(tmp2->m_dataPath);
            free(tmp2->m_instructmentPath);
            break;
        }
        case CREATESTRUCT:
        {
            CreateStructPoint tmp3 = (CreateStructPoint)root;
            free(tmp3->name);
            freeStruct(CREATEFIELDSTRUCT,tmp3->fields);
            free(tmp3);
            break;
        }
        case CREATEFIELDSTRUCT:
        {
            CreateFieldStructPoint next,now = (CreateFieldStructPoint) root;
            while(now != NULL){
                next = now->next;
                free(now->name);
                free(now);
                now = next;
            }
            break;
        }
        case  DELETESTRUCT:
        {
            DeleteStructPoint dsp = (DeleteStructPoint) root;

            free(dsp->table);
            if(dsp->cp != NULL) freeStruct(CONDITIONSTRUCT,dsp->cp);
            free(dsp);
            break;
        }
        case CONDITIONSTRUCT:
        {
            ConditionStructPoint cp = (ConditionStructPoint) root;

            if(cp->table != NULL){
                free(cp->table);
            }

            if( cp-> value != NULL){
                free(cp->value);
            }

            if(cp->left != NULL){
                freeStruct(CONDITIONSTRUCT,cp->left);
            }

            if(cp->right != NULL){
                freeStruct(CONDITIONSTRUCT,cp->right);
            }

            free(cp);
            break;
        }
        case INSERTSTRUCT:
        {
            InsertStructPoint isp = (InsertStructPoint)root;

            free(isp->table);
            freeStruct(INSERTFIELDSTRUCT,isp->fields);
            freeStruct(INSERTITEMSTRUCT,isp->items);
            free(isp);
            break;
        }
        case INSERTFIELDSTRUCT:
        {
            InsertFieldStructPoint  next,now = (InsertFieldStructPoint)root;
            while(now != NULL){
                next = now->next;
                free(now->fieldName);
                free(now);
                now = next;
            }
            break;
        }
        case INSERTITEMSTRUCT:
        {
            InsertItemStructPoint  next,now = (InsertItemStructPoint)root;
            while(now != NULL){
                next = now->next;
                free(now->value);
                free(now);
                now = next;
            }
            break;
        }
        case UPDATESTRUCT:
        {
            UpdateStructPoint usp = (UpdateStructPoint)root;
            free(usp->table);
            if(usp->cp != NULL)
            freeStruct(CONDITIONSTRUCT,usp->cp);
            freeStruct(UPDATEFIELDSTRUCT,usp->fp);
            free(usp);
            break;
        }
        case UPDATEFIELDSTRUCT:
            {
            UpdatedFieldStructPoint next,now = (UpdatedFieldStructPoint) root;

            while(now != NULL){
                next = now->next;
                free(now->name);
                free(now->value);
                free(now);
                now = next;
            }
            }
            break;
        case SELECTEDFIELDSTRUCT:
        {
            SelectedFieldStructPoint next,now = (SelectedFieldStructPoint) root;
            while(now != NULL){
                next = now->next;
                
                if(now->table != NULL) {free(now->table);}
                if(now->alias != NULL) {free(now->alias);}
                free(now->field);
                free(now);

                now = next;
            }
        }
            break;
        case SELECTEDTABLELIST:
        {
            SelectedTableStructPoint next,now = (SelectedTableStructPoint) root;
            while(now != NULL){
                next = now->next;
                free(now->table);
                free(now);
                now = next;
            }
            break;
        }
        case SELECTSTRUCT:
        {
            SelectStructPoint ssp = (SelectStructPoint)root;
            freeStruct(SELECTEDTABLELIST,ssp->tp);
            if(ssp->fp != NULL)
            freeStruct(SELECTEDFIELDSTRUCT,ssp->fp);
            if(ssp->cp != NULL)
            freeStruct(CONDITIONSTRUCT,ssp->cp);
            free(ssp);
            break; 
        } 
        case SELECTRESULTSTRUCT:
        {
            SelectResultStructPoint sp = (SelectResultStructPoint)root;
            SelectResultItemStructPoint next,now = sp->data;
            while(now != NULL){
                next = now->next;
                free(now->space);
                free(now);
                now = next;
            }
            free(sp);
            break;
        }
    }
}

bool writeBackTableList(){
    char * m_tableListFile = strpathcat(m_usingDatabase,"tableList.sdb");
    FILE * fp = fopen(m_tableListFile,"w");
    fseek(fp,0,SEEK_SET);
    if(fp == NULL){
        handleError(CONFIG_TABLE_CREATE_ERROR,m_tableListFile);
        free(m_tableListFile);
        return false;
    }  else{
        TableListStructPoint tmp = m_tlsp;
        while(tmp != NULL){
            fprintf(fp,"%s\n",tmp->name);
            tmp = tmp->next;
        }
        fclose(fp);
        return true;
    }
}

TableListStructPoint readTableList(){
    char * m_tableListFile = strpathcat(m_usingDatabase,"tableList.sdb");
    FILE * fp = fopen(m_tableListFile,"r");
    if(fp == NULL){
        handleError(CONFIG_TABLE_CREATE_ERROR,m_tableListFile);
        free(m_tableListFile);
        return NULL;
    }   
    char buffer[128];
    TableListStructPoint head,now;
    head = NULL;
    while(!feof(fp)){
        buffer[0] = 0;
        fscanf(fp,"%s",buffer);
        if(strlen(buffer) < 5){
            continue;
        }
        if(head == NULL){
            head = (TableListStructPoint)malloc(sizeof(TableListStruct));
            now = head;
        }else{
            now->next = (TableListStructPoint)malloc(sizeof(TableListStruct));
            now = now->next;
        }
        strcpy(now->name,buffer);
        now->next = NULL;
    }
    fclose(fp);
    return head;
}

void help(){
    FILE * ins_fp = fopen(m_databaseConfig->m_instructmentPath,"rb");
    if(ins_fp == NULL){
        handleError(FILE_OPEN_ERROR,m_databaseConfig->m_instructmentPath);
        return;
    }
    while(!feof(ins_fp))
    {
        printf("%c",getc(ins_fp));
    }
    fclose(ins_fp);
}

// use database;
void useDatabase(char * dbname){
    char * tmp = m_usingDatabase;
    m_usingDatabase  = strpathcat(m_databaseConfig->m_dataPath,dbname);
    
    // Judge the database exists.
    if(access(m_usingDatabase,F_OK) != 0){
        handleError(DATABASE_NOT_EXIST_ERROR,dbname);
        free(m_usingDatabase);
        // Restore
        m_usingDatabase = tmp;
        return;
    }

    if(m_tlsp != NULL){
        // free
        freeStruct(TABLELIST,m_tlsp);
    }

    if(tmp != NULL){
        // free
        free(tmp);
    }

    // get new List
    m_tlsp = readTableList();

    printf("now database is %s!\n",m_usingDatabase);
    free(dbname);
    return;
}

// create database dbname;
void createDatabase(char *dbname){
    char * m_dbDir = strpathcat(m_databaseConfig->m_dataPath,dbname);
    // The creator has the database primission.
    if(mkdir(m_dbDir,0777) == -1){
        perror("mkdir");
        handleError(CREATE_DATABASE_ERROR,m_dbDir);
        free(m_dbDir);
        return;
    }
    char * m_tableListFile = strpathcat(m_dbDir,"tableList.sdb"); 

    FILE * tfp = fopen(m_tableListFile,"w+");
    if(tfp == NULL){
        handleError(CONFIG_TABLE_CREATE_ERROR,m_usingDatabase);
    }

    fclose(tfp);
    free(m_dbDir);
    free(m_tableListFile);
    free(dbname);
    printf("success!\n");
};

int printTableItem(TableListStructPoint tmp,int max){
    max = max >= strlen(tmp->name) ? max : strlen(tmp->name);
    if(tmp->next == NULL){
        int cnt = calTabCnt(max);
        borderPrint(cnt);
        printf("+\n");

        contentPrint("tables",cnt);
        printf("|\n");

        borderPrint(cnt);
        printf("+\n");

        contentPrint(tmp->name,cnt);
        printf("|\n");
    
    }else{
        max = printTableItem(tmp->next,max);
        contentPrint(tmp->name,calTabCnt(max));
        printf("|\n");
    }
    return max;
}

void showTables(){
    if( m_tlsp == NULL){
        printf("empty database!\n");
        return;
    }
    int max = printTableItem(m_tlsp,6);
    int cnt = calTabCnt(max);
    borderPrint(cnt);
    printf("+\n");
}

int printDatabaseItem(DIR * dir,int max){

    struct dirent *ptr;
    if((ptr = readdir(dir)) == NULL){
        int cnt = calTabCnt(max);
        borderPrint(cnt);
        printf("+\n");

        contentPrint("databases",cnt);
        printf("|\n");

        borderPrint(cnt);
        printf("+\n");
        return max;
    }

    if(!strcmp(ptr->d_name,".") || !strcmp(ptr->d_name,"..")){
        max = printDatabaseItem(dir,max);
        return max;
    }

    max = max >= strlen(ptr->d_name) ? max : strlen(ptr->d_name);
    max = printDatabaseItem(dir,max);
    contentPrint(ptr->d_name,calTabCnt(max));
    printf("|\n");
    return max;
}

// Show databases;
void showDatabases(){

    DIR * dir;
    dir = opendir(m_databaseConfig->m_dataPath);
    int cnt = calTabCnt(printDatabaseItem(dir,9));
    borderPrint(cnt);
    printf("+\n");
}


void dropDatabase(char * dbname){
    char * m_dbDir = strpathcat(m_databaseConfig->m_dataPath,dbname);

    struct dirent * dp;

    DIR * dir = opendir(m_dbDir);
    if(dir == NULL){
        handleError(DIRECTORY_OPEN_ERROR,dbname);
        free(m_dbDir);
        return;
    }
    char path[512];

    while((dp = readdir(dir) ) != NULL){
        if(!strcmp(dp->d_name,".") || !strcmp(dp->d_name,"..")){continue;}
        sprintf(path,"%s/%s",m_dbDir,dp->d_name);
        remove(path);
    } 

    closedir(dir);

    rmdir(m_dbDir);

    free(m_dbDir);

    free(dbname);

    printf("success!\n");
}


void handleError(enum EXECEUTERROR err,void * data){
    switch(err){
        case CONFIG_FILE_OPEN_ERROR:
            printf("%d error: Can not open config file '%s'!\n",error,(char *)data);break;
        case CREATE_DATABASE_ERROR:
            printf("%d error: Fail to create database in path '%s'!\n",error,(char *)data);break;
        case DATABASE_NOT_EXIST_ERROR:
            printf("%d error: Database '%s' does not exist !\n",error,(char *)data);
        case CONFIG_TABLE_CREATE_ERROR:
            printf("%d error: Can not create tableList.sdb in database '%s'!\n",error,(char *)data);
        case FILE_OPEN_ERROR:
            printf("%d error: Can not open the file '%s'!\n",error,(char *)data);
        case DIRECTORY_OPEN_ERROR:
            printf("%d error: Can not open the directory '%s'/'%s'!May be the Database '%s' does not exist!\n",error,m_databaseConfig->m_dataPath,(char *)data,(char *)data);
    }
}

char * strpathcat(char * prefix,char * other){
    char * result = (char *)malloc(sizeof(char) * (strlen(prefix) + strlen(other) + 2));
    strcpy(result,prefix);
    strcat(result,"/");
    strcat(result,other);
    return result;
}

void _select(SelectStructPoint  data){

    if(m_usingDatabase == NULL){
        printf("error: No database is selected!\n");
        freeStruct(CREATESTRUCT,data);
        return;
    }

    TableListStructPoint pre,tmp = m_tlsp;
    pre = NULL;
    char name[100];


    strcpy(name,data->tp->table);
    strcat(name,".idb");


    // 只有单表查询
    while(tmp != NULL){
        if(!strcmp(tmp->name,name)){
            break;
        }
        pre = tmp;
        tmp = tmp->next;
    }

    if(tmp == NULL){
        printf("error: the table not exists!");
        return;
    }

    char * tablePath = strpathcat(m_usingDatabase,name);
    FILE * fp = fopen(tablePath,"r");

    SelectResultStructPoint srsp = idb_select_single_table(fp,data);

    if(srsp->success == false){
        printf("fail!\n");
        return;
    }

    FileHeaderStructPoint fhsp = idb_getFileHeader(fp);

    KeyStruct keys[fhsp->keyNumber];
    idb_readKeyStruct(fp,fhsp->keyNumber,keys);

    int offset[fhsp->keyNumber];

    offset[0] = 0;
    int oneSize = fhsp->recordSize - 4;
    for(int i = 1;i < fhsp->keyNumber;i++){
        if(keys[i - 1].flag == FIELD_INT){
            offset[i] = offset[i - 1] + 4;
        }else if(keys[i - 1].flag == FIELD_DOUBLE){
            offset[i] = offset[i - 1] + 8;
        }else{
            offset[i] = offset[i - 1] + keys[i - 1].length;
        }
    }

    int cnt[100];
    int off[100];
    int typ[100];

    int count = 0;
    SelectedFieldStructPoint sftmp = data->fp;
    if(data->fp == NULL){
        int  len;
        for(int i = 0;i < fhsp->keyNumber;i++){
            if (keys[i].flag == FIELD_INT) {
                len = strlen(keys[i].name) + 2;
                cnt[i] = 17 > len ? calTabCnt(18) : calTabCnt(len);
                off[i] = offset[i];
                typ[i] = FIELD_INT;
            } else if (keys[i].flag == FIELD_DOUBLE) {
                len = strlen(keys[i].name) + 2;
                cnt[i] = 17 > len ? calTabCnt(18) : calTabCnt(len);
                off[i] = offset[i];
                typ[i] = FIELD_DOUBLE;
            } else {
                len = strlen(keys[i].name) + 2;
                cnt[i] = keys[i].length > len ? calTabCnt(keys[i].length) : calTabCnt(len);
                off[i] = offset[i];
                typ[i] = FIELD_STRING;
            }
        }
        count = fhsp->keyNumber;

    }else {

        while (sftmp != NULL) {
            int i = 0;
            for (; i < fhsp->keyNumber; i++) {
                if (!strcmp(keys[i].name, sftmp->field)) {
                    break;
                }
            }

            if (i == fhsp->keyNumber) {
                printf("error: can't recognize the field %s!", sftmp->field);
                freeStruct(SELECTSTRUCT, data);
                freeStruct(SELECTRESULTSTRUCT, srsp);
                fclose(fp);
                return;
            }


            int len = 0;
            if (keys[i].flag == FIELD_INT) {
                len = strlen(keys[i].name) + 2;
                cnt[count] = 17 > len ? calTabCnt(18) : calTabCnt(len);
                off[count] = offset[i];
                typ[count] = FIELD_INT;
            } else if (keys[i].flag == FIELD_DOUBLE) {
                len = strlen(keys[i].name) + 2;
                cnt[count] = 17 > len ? calTabCnt(18) : calTabCnt(len);
                off[count] = offset[i];
                typ[count] = FIELD_DOUBLE;
            } else {
                len = strlen(keys[i].name) + 2;
                cnt[count] = keys[i].length > len ? calTabCnt(keys[i].length) : calTabCnt(len);
                off[count] = offset[i];
                typ[count] = FIELD_STRING;
            }
            count++;
            sftmp = sftmp->next;
        }
    }

    int number = srsp->number;


    int j;
    for(j = 0;j < count;j++){
        borderPrint(cnt[j]);
    }
    printf("+\n");

    if(data->fp != NULL) {
        sftmp = data->fp;

        for (j = 0; j < count; j++) {
            contentPrint(sftmp->field, cnt[j]);
            sftmp = sftmp->next;
        }
        printf("|\n");
    }else{
        for(j = 0;j < count;j++){
            contentPrint(keys[j].name,cnt[j]);
        }
        printf("|\n");
    }

    for(j = 0;j < count;j++){
        borderPrint(cnt[j]);
    }
    printf("+\n");

    SelectResultItemStructPoint res = srsp->data;
    int spaceUse = 0;

    while(number != 0){

        if(spaceUse == 100){
            res = res->next;
            spaceUse = 0;
        }

        char * idx = (char *)res->space + oneSize * spaceUse;
        for(int k = 0;k < count;k++){
            if(typ[k] == FIELD_INT){
                contentIntPrint((int *)(idx + off[k]),cnt[k]);
            }else if(typ[k] == FIELD_DOUBLE){
                contentDoublePrint((double *)(idx + off[k]),cnt[k]);
            }else{
                contentPrint(idx + off[k],cnt[k]);
            }
        }
        printf("|\n");
        spaceUse ++;
        number --;
    }

    for(j = 0;j < count;j++){
        borderPrint(cnt[j]);
    }
    printf("+\n");

    printf("Total %d records!\n",srsp->number);

    fclose(fp);
    freeStruct(SELECTSTRUCT,data);
    freeStruct(SELECTRESULTSTRUCT,srsp);

    return;

}

void insert(InsertStructPoint data){

    if(m_usingDatabase == NULL){
        printf("error: No database is selected!\n");
        freeStruct(CREATESTRUCT,data);
        return;
    }

    TableListStructPoint pre,tmp = m_tlsp;
    pre = NULL;
    char name[100];


    strcpy(name,data->table);
    strcat(name,".idb");


    // 只有单表查询
    while(tmp != NULL){
        if(!strcmp(tmp->name,name)){
            break;
        }
        pre = tmp;
        tmp = tmp->next;
    }

    if(tmp == NULL){
        printf("error: the table not exists!");
    }

    char * tablePath = strpathcat(m_usingDatabase,name);
    FILE * fp = fopen(tablePath,"r+");

    if(idb_insert(fp,data) == true){
        printf("success!\n");
        freeStruct(INSERTSTRUCT,data);
        fclose(fp);
        return;
    }

    printf("fail!\n");
    fclose(fp);
    return;

}

void update(UpdateStructPoint data){

    if(m_usingDatabase == NULL){
        printf("error: No database is selected!\n");
        freeStruct(CREATESTRUCT,data);
        return;
    }

    TableListStructPoint pre,tmp = m_tlsp;
    pre = NULL;
    char name[100];


    strcpy(name,data->table);
    strcat(name,".idb");


    // 只有单表查询
    while(tmp != NULL){
        if(!strcmp(tmp->name,name)){
            break;
        }
        pre = tmp;
        tmp = tmp->next;
    }

    if(tmp == NULL){
        printf("error: the table not exists!");
        return;
    }

    char * tablePath = strpathcat(m_usingDatabase,name);
    FILE * fp = fopen(tablePath,"r+");

    ModifyResultStructPoint mrsp = idb_update(fp,data);


    if(mrsp->success){
        printf("success to modify %d records!\n",mrsp->modifyNumber);
    }else{
        printf("fail!\n");
    }
    fclose(fp);
    free(mrsp);
    freeStruct(UPDATESTRUCT,data);

    return;

}

void _delete(DeleteStructPoint data){

    if(m_usingDatabase == NULL){
        printf("error: No database is selected!\n");
        freeStruct(CREATESTRUCT,data);
        return;
    }

    TableListStructPoint pre,tmp = m_tlsp;
    pre = NULL;
    char name[100];


    strcpy(name,data->table);
    strcat(name,".idb");


    // 只有单表查询
    while(tmp != NULL){
        if(!strcmp(tmp->name,name)){
            break;
        }
        pre = tmp;
        tmp = tmp->next;
    }

    if(tmp == NULL){
        printf("error: the table not exists!\n");
        return;
    }

    char * tablePath = strpathcat(m_usingDatabase,name);
    FILE * fp = fopen(tablePath,"r+");

    ModifyResultStructPoint mrsp =  idb_delete(fp,data);

    fclose(fp);
    if(mrsp->success){
        printf("success to modify %d records!\n",mrsp->modifyNumber);
    }else{
        printf("fail!\n");
    }
    free(mrsp);
    freeStruct(DELETESTRUCT,data);
}

void createTable(CreateStructPoint data){
    if(m_usingDatabase == NULL){
        printf("error: No database is selected!\n");
        freeStruct(CREATESTRUCT,data);
        return;
    }

    TableListStructPoint pre,tmp = m_tlsp;

    pre = NULL;

    char name[100];

    strcpy(name,data->name);
    strcat(name,".idb");

    while(tmp != NULL){
        if(!strcmp(tmp->name,name)){
            break;
        }
        pre = tmp;
        tmp = tmp->next;
    }

    if(tmp != NULL){
        printf("error: the table already exists!");
        return;
    }

    char * tablePath = strpathcat(m_usingDatabase,name);
    FILE * fp = fopen(tablePath,"w");
    bool result = idb_create(fp,data->fields);
    if (result == true){
        TableListStructPoint tbp = (TableListStructPoint)malloc(sizeof(TableListStruct));
        tbp->next = NULL;
        strcpy(tbp->name,name);

        if(pre == NULL){
            m_tlsp = tbp;
        }else{
            pre->next = tbp;
        }

        writeBackTableList();
        printf("success!\n");
    }else{
        printf("error: can't create table!\n");
    }
    fclose(fp);
    return;
}

void dropTable(char * name){

    if(m_usingDatabase == NULL){
        printf("error: No database is selected!\n");
        free(name);
        return;
    }

    char a[100];

    strcpy(a,name);
    strcat(a,".idb");

    TableListStructPoint  pre,tmp = m_tlsp;
    pre = NULL;
    while(tmp != NULL){
        if(!strcmp(tmp->name,a)){
            break;
        }
        pre = tmp;
        tmp = tmp->next;
    }

    if(tmp == NULL){
        printf("error: can't find the table '%s'!\n",name);
        free(name);
        return;
    }

    char * tablePath = strpathcat(m_usingDatabase,a);
    remove(tablePath);
    free(tablePath);

    if(pre == NULL){
        m_tlsp = tmp->next;
        free(tmp);
    }else{
        pre->next = tmp->next;
        free(tmp);
    }

    writeBackTableList();

    printf("success!\n");
    return;
}

void desc(char * data){
    if(m_usingDatabase == NULL){
        printf("error: No database is selected!\n");
        free(data);
        return;
    }

    TableListStructPoint pre,tmp = m_tlsp;
    pre = NULL;
    char name[100];


    strcpy(name,data);
    strcat(name,".idb");


    // 只有单表查询
    while(tmp != NULL){
        if(!strcmp(tmp->name,name)){
            break;
        }
        pre = tmp;
        tmp = tmp->next;
    }

    if(tmp == NULL){
        printf("error: the table not exists!\n");
        return;
    }

    char * tablePath = strpathcat(m_usingDatabase,name);
    FILE * fp = fopen(tablePath,"r+");

    FileHeaderStructPoint fhsp = idb_getFileHeader(fp);

    KeyStruct keys[fhsp->keyNumber];
    idb_readKeyStruct(fp,fhsp->keyNumber,keys);
    int cnt = calTabCnt(20);

    borderPrint(cnt);
    borderPrint(2);
    printf("+\n");

    contentPrint("KEY",cnt);
    contentPrint("TYPE",2);
    printf("|\n");

    borderPrint(cnt);
    borderPrint(2);
    printf("+\n");

    for(int i = 0;i < fhsp->keyNumber;i++){
        switch (keys[i].flag) {
            case FIELD_INT:
                contentPrint(keys[i].name,cnt);
                contentPrint("INT",2);
                printf("|\n");
                break;
            case FIELD_DOUBLE:
                contentPrint(keys[i].name,cnt);
                contentPrint("DOUBLE",2);
                printf("|\n");
                break;
            case FIELD_STRING:
                contentPrint(keys[i].name,cnt);
                char data[100];
                sprintf(data,"CHAR(%d)",keys[i].length);
                contentPrint(data,2);
                printf("|\n");
                break;
        }
    }
    borderPrint(cnt);
    borderPrint(2);
    printf("+\n");

    free(fhsp);
    free(tablePath);
    fclose(fp);
    return;

}

void executeSQL(void * syntaxTree,int type){
    printf("debug: executeSQL!%d\n",type);
    switch(type){
        case DESCSQL:
            desc((char *)syntaxTree);
            break;
        case USESQL:
            useDatabase((char *)syntaxTree);
            break;
        case HELPSQL:
            help();
            break;
        case CREATEDATABASESQL:
            createDatabase((char *) syntaxTree);
            break;
        case SHOWDATABASESSQL:
            showDatabases();
            break;
        case EXITSQL:
            _exitDatabase();
            break;
        case DROPDATABASESQL:
            dropDatabase((char *)syntaxTree);
            break;
        case SHOWTABLESSQL:
            showTables();
            break;
        case SELECTSQL:
            _select((SelectStructPoint) syntaxTree);
            break;
        case INSERTSQL:
            insert((InsertStructPoint) syntaxTree);
            break;
            case UPDATESQL:
            update((UpdateStructPoint) syntaxTree);
            break;
        case DELETESQL:
            _delete((DeleteStructPoint) syntaxTree);
            break;
        case CREATESQL:
            createTable((CreateStructPoint) syntaxTree);
            break;
        case DROPTABLESQL:
            dropTable((char *)syntaxTree);
            break;
    }
}
